home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 7: Sunsite / Linux Cubed Series 7 - Sunsite Vol 1.iso / libs / x / xview / xview3.004 / xview3 / usr / openwin / include / xview_private / ndet.h < prev    next >
Encoding:
C/C++ Source or Header  |  1996-05-29  |  15.3 KB  |  385 lines

  1. /*      @(#)ndet.h 20.13 93/06/28 SMI      */
  2.  
  3. /*
  4.  *    (c) Copyright 1989 Sun Microsystems, Inc. Sun design patents 
  5.  *    pending in the U.S. and foreign countries. See LEGAL NOTICE 
  6.  *    file for terms of the license.
  7.  */
  8.  
  9. /*
  10.  * Ndet.h - Private header file for the detector part of the notifier.
  11.  * The detector is responsible for noticing the occurrence of UNIX
  12.  * events.  It maintains a complete list of clients that are awaiting
  13.  * notification.  It maintains a per client list of conditions that the
  14.  * client is awaiting.
  15.  */
  16.  
  17. #ifndef    NDET_DEFINED
  18. #define    NDET_DEFINED
  19.  
  20. /*
  21. ********************** Detector Loop Notes ****************************
  22. Here is some notes on the detector loop:
  23.  
  24. 1) Any time that a notification changes (new, added, removed, modified),
  25. the appropriate "changed" constant is ored into ndet_flags (see below). 
  26. To determine the things that the notifier needs to ask UNIX
  27. to watch for (fd activity, signals, itimers) requires scanning
  28. all clients and notifications.  Comparing the result of this scan
  29. with what the notifier is already watching for determines what work
  30. has to be done to change what UNIX is doing.
  31.  
  32. 2) A cycle of the notification loop can be entered in a variety of ways.
  33.  
  34. a) Notify_start can be called by the top level of the application.
  35.  
  36. b) When select is called, if notifications are being dispatched then
  37. a real select system call is made.  Otherwise, a private notifier
  38. client is generated that sets conditions equivalent to the select's
  39. arguments.  Result bit masks and itimer expired flags are initialized.
  40. Notify_start is then called.  If any of the select client's routines
  41. are called, result bit masks and/or itimer expired flags are set.
  42. In addition, notify_stop is called.  When notify_start returns, its
  43. error code, errno, the result bit masks and/or itimer expired flags
  44. are used to generate return values.
  45.  
  46. c) When read is called, if notifications are being dispatched then
  47. a real read system call is made.  Otherwise, a private notifier
  48. client is generated that sets an input pending condition for the read
  49. fd.  A input pending flag is initialized.  Notify_start is then called.
  50. If the read client's input pending routine is called, the input
  51. pending flag is set.  In addition, notify_stop is called.  When
  52. notify_stop returns, its error code, errno and the input pending flag
  53. are used to figure out if a real read system call is to be done.
  54. If so, a real read system call is done and the results returned.
  55.  
  56.  
  57. ********************** Public Interface Supporting *********************
  58. The public programming interface that the detector supports follows:
  59.  
  60. notify_set_input_func
  61. notify_set_output_func
  62. notify_set_exception_func
  63. notify_set_itimer_func
  64. notify_set_signal_func
  65. notify_set_wait3_func
  66. notify_set_destroy_func
  67. notify_set_event_func
  68. notify_set_prioritizer_func
  69.  
  70. notify_get_itimer_value
  71. notify_post_event
  72. notify_post_destroy
  73. notify_veto_destroy
  74.  
  75. notify_start
  76. notify_stop
  77. notify_die
  78. notify_remove
  79.  
  80. fcntl
  81. read
  82. select
  83.  
  84. notify_get_input_func
  85. notify_get_output_func
  86. notify_get_exception_func
  87. notify_get_itimer_func
  88. notify_get_signal_func
  89. notify_get_wait3_func
  90. notify_get_destroy_func
  91. notify_get_event_func
  92. notify_get_prioritizer_func
  93.  
  94. */
  95.  
  96. /*
  97.  * The detector uses ndet_/NDET_ name prefices.
  98.  */
  99.  
  100. /*
  101.  * Detector global data
  102.  */
  103. extern    u_int    ndet_flags;        /* Flags */
  104. #define    NDET_STOP        0x01    /* Ntfy_stop called */
  105. #define    NDET_FD_CHANGE        0x02    /* A fd condition changed */
  106. #define    NDET_SIGNAL_CHANGE    0x04    /* A signal condition changed */
  107. #define    NDET_REAL_CHANGE    0x08    /* A real itimer condition changed */
  108. #define    NDET_VIRTUAL_CHANGE    0x10    /* A virtual itimer condition changed */
  109. #define    NDET_WAIT3_CHANGE    0x20    /* A wait3 condition changed */
  110. #define    NDET_DISPATCH        0x40    /* Calling ndis_dispatch (used to know
  111.                        if should do real or notifier
  112.                        version of read and select) */
  113. #define    NDET_REAL_POLL        0x80    /* Real itimer wants to poll, invalid if
  114.                        ndet_flags & NDET_REAL_CHANGE */
  115. #define    NDET_VIRTUAL_POLL    0x100    /* Virtual itimer wants to poll, invalid
  116.                        if ndet_flags & NDET_VIRTUAL_CHANGE*/
  117. #define    NDET_POLL        (NDET_REAL_POLL|NDET_VIRTUAL_POLL)
  118.                     /* Do polling in select */
  119. #define    NDET_INTERRUPT        0x200    /* Set when handling a signal interrupt
  120.                        so that know not to go to system
  121.                        heap */
  122. #define    NDET_STARTED        0x400    /* In ntfy_start */
  123. #define    NDET_EXIT_SOON        0x800    /* Notifier auto SIGTERM triggered,
  124.                        exit(1) after finish dispatch */
  125. #define    NDET_STOP_ON_SIG    0x1000    /* Notifier select client wants to break
  126.                        if get a signal during real select */
  127. #define    NDET_VETOED        0x2000    /* Notify_veto_destroy called */
  128. #define    NDET_ITIMER_ENQ        0x4000    /* Itimer notification enqueued */
  129. #define    NDET_NO_DELAY        0x8000    /* Caller of notify_start wants single
  130.                        time around the loop */
  131. #define    NDET_DESTROY_CHANGE    0x10000    /* A destroy condition changed */
  132. #define    NDET_CONDITION_CHANGE    (NDET_FD_CHANGE|NDET_SIGNAL_CHANGE|\
  133.     NDET_REAL_CHANGE|NDET_VIRTUAL_CHANGE|NDET_WAIT3_CHANGE|NDET_DESTROY_CHANGE)
  134.                     /* Combination of condition changes */
  135.  
  136. extern    NTFY_CLIENT *ndet_clients;    /* Active clients */
  137. extern    NTFY_CLIENT *ndet_client_latest;/* Latest Notify_client=>NTFY_CLIENT
  138.                        conversion success: for fast lookup
  139.                        (nulled when client removed) */
  140.  
  141. extern    fd_set    ndet_fndelay_mask;    /* Mask of non-blocking read fds
  142.                        (maintained by fcntl) */
  143. extern    fd_set    ndet_fasync_mask;    /* Mask of fds that generate SIGIO
  144.                        when data ready (maintained by
  145.                        fcntl) */
  146.  
  147. extern    fd_set    ndet_ibits, ndet_obits, ndet_ebits;
  148.                     /* Select bit masks (invalid if
  149.                        ndet_flags & NDET_FD_CHANGE) */
  150. extern    struct    timeval ndet_polling_tv;/* Tv with select type polling value */
  151.  
  152. extern    sigset_t   ndet_sigs_auto;    /* Bits that indicate which signals the
  153.                        notifier is automatically catching
  154.                        (SIGIO, SIGURG, SIGCHLD, SIGTERM,
  155.                        SIGALRM, SIGVTALRM) */
  156. extern    void    ndet_toggle_auto();    /* When some condition that the notifier
  157.                        is interested in changes, call this
  158.                        to adjust ndet_sigs_auto (TBD reword)
  159.                        (u_int obld_bits, sig) */
  160. extern    Notify_value ndet_auto_sig_func();/* (Notify_client nclient,
  161.                         int signal, Notify_signal_mode) */
  162. extern    Notify_client ndet_auto_nclient;/* Private notifier client for auto
  163.                        signal handling */
  164. extern    NTFY_ENUM ndet_auto_sig_send();    /* Tell auto sig manager that one of
  165.                        its condition has occurred
  166.                        (NTFY_CLIENT *client,
  167.                         NTFY_CONDITION *condition,
  168.                         NTFY_ENUM_DATA context) */
  169.  
  170. extern  sigset_t  ndet_sigs_managing;   /* Signals that are managing (invalid if
  171.                        ndet_flags & NDET_SIGNAL_CHANGE) */
  172. extern    sigset_t  ndet_sigs_received;    /* Records signals received */
  173. extern    void    ndet_enable_sig();    /* Call this routine (other than from
  174.                        ndet_fig_sig_change) when you need
  175.                        to make sure that a signal is being
  176.                        caught but don't want to go through
  177.                        the whole process of globally finding
  178.                        out who else needs it. (u_int sig) */
  179. extern    void    ndet_send_delayed_sigs();/* Process any async signal conditions
  180.                        that have may have accumulated during
  181.                        a critical section. */
  182.  
  183. extern    Notify_func ndet_set_fd_func();    /* (Notify_client nclient,
  184.                         Notify_func func, int fd
  185.                         NTFY_TYPE type) */
  186. extern    Notify_func ndet_get_fd_func();    /* (Notify_client nclient,
  187.                         int fd, NTFY_TYPE type) */
  188. extern    Notify_func ndet_get_func();    /* (Notify_client nclient,
  189.                         NTFY_TYPE type, NTFY_DATA data,
  190.                         int use_data) */
  191. extern    ndet_check_fd();        /* Returns 0 if all OK else -1 and
  192.                        sets notify_errno to NOTIFY_BADF
  193.                        (int fd) */
  194.  
  195. extern    ndet_check_sig();        /* Returns 0 if all OK else -1 and sets
  196.                        notify_errno to NOTIFY_BAD_SIGNAL
  197.                        (int sig) */
  198. extern    ndet_check_mode();        /* Returns 0 if all OK else -1 and sets
  199.                        notify_errno to NOTIFY_INVAL.  Sets
  200.                        type_ptr if not null.
  201.                        (Notify_signal_mode mode,
  202.                         NTFY_TYPE *type_ptr) */
  203.  
  204. extern    ndet_check_which();        /* Turn itimer which into type.
  205.                        Returns 0 if all OK else -1 and sets
  206.                        notify_errno to NOTIFY_INVAL.  Sets
  207.                        type_ptr if not null.
  208.                        (int which, NTFY_TYPE *type_ptr) */
  209. #define       ndet_tv_equal(_a, _b)   \
  210.       (_a.tv_sec == _b.tv_sec && _a.tv_usec == _b.tv_usec)
  211. #define    ndet_tv_polling(tv) ndet_tv_equal((tv), NOTIFY_POLLING_ITIMER.it_value)
  212. extern    struct timeval ndet_tv_subt();    /* Subtracts b from a.  Will round down
  213.                        any NOTIFY_POLLING_ITIMER.it_value
  214.                        results to {0,0}.  This is to prevent
  215.                        the notifier from generating a
  216.                        polling timer
  217.                        (struct timeval a, b) */
  218. extern    struct timeval ndet_tv_min();    /* Find min of b and a.
  219.                        (struct timeval a, b) */
  220.  
  221. extern    struct timeval ndet_real_min();    /* Figure the interval that has
  222.                        transpired since this real interval
  223.                        timer has been set.  The difference
  224.                        between how much time the timer wants
  225.                        to wait and how long it has waited is
  226.                        the amount of time left to wait.
  227.                        The time left to wait is returned.
  228.                        (NTFY_ITIMER *ntfy_itimer,
  229.                         struct timeval current_tv) */
  230. extern    struct timeval ndet_virtual_min(); /* Update the interval until
  231.                         expiration by subtracting the amount
  232.                         of time on the process interval
  233.                         timer (current_tv) from the value of
  234.                         the process interval timer when it
  235.                         was last looked at by this client
  236.                         (ntfy_itimer->set_tv).
  237.                         Return the amount of time that this
  238.                         virtual interval timer has to go
  239.                         before expiration
  240.                         (ntfy_itimer->itimer.it_value).
  241.                         Need to update ntfy_itimer->set_tv
  242.                         with this value after calling
  243.                         ndet_virtual_min.
  244.                         (NTFY_ITIMER *ntfy_itimer,
  245.                          struct timeval current_tv) */
  246. extern    void ndet_reset_itimer_set_tv();/* Reset ntfy_itimer->set_tv based on
  247.                        type (NTFY_CONDITION *condition) */
  248.  
  249. /*
  250.  * NDET_ENUM_SEND is used to send the results of select around to conditions.
  251.  */
  252. typedef struct ndet_enum_send {
  253.     fd_set    ibits;            /* Input devices selected */
  254.     fd_set    obits;            /* Output devices selected */
  255.     fd_set    ebits;            /* Exception devices selected */
  256.     sigset_t   sigs;        /* Signals to process */
  257.     NTFY_WAIT3_DATA *wait3;        /* Results of wait3 system call */
  258.     struct  timeval current_tv;    /* NTFY_REAL_ITIMER time-of-day (now)
  259.                        NTFY_VIRTUAL_ITIMER current itimer
  260.                        it_value */
  261. } NDET_ENUM_SEND;
  262.  
  263. /* 
  264.  * When recomputing itimers, NDET_ENUM_ITIMER is used to pass the context 
  265.  * for the real or virtual itimer around. 
  266.  */ 
  267. typedef    struct  ndet_enum_itimer {
  268.     int        enqueued;    /* Not zero if enqd notification */
  269.     NTFY_TYPE    type;        /* One of NTFY_*_ITIMER */
  270.     u_int        polling_bit;    /* One of NDET_*_POLL */
  271.     int        signal;        /* SIGALRM | SIGVTALRM */
  272.     int        which;        /* VIRTUAL_ITIMER | REAL_ITIMER */
  273.     struct timeval    (*min_func)();    /* Returns the interval that a given
  274.                        itimer needs to wait until expiration
  275.                        (virtual itimer resets set_time) */
  276.     Notify_value    (*expire_func)();/* Called when itimer expiration
  277.                        detected */
  278.     struct timeval    current_tv;    /* Real is time-of-day, virtual is
  279.                        current virtual itimer value */
  280.     struct timeval    min_tv;        /* Global min of min_func return value*/
  281. } NDET_ENUM_ITIMER;
  282. extern    struct timeval    ndet_virtual_min();
  283. extern    struct timeval    ndet_real_min();
  284. extern    void ndet_update_virtual_itimer();/* Some virtual itimer related
  285.                        condition has changed.  Update all
  286.                        virtual itimers.  Determine minimum
  287.                        wait and set virtual itimer.  Enable
  288.                        (disable) notifier auto signal
  289.                        catching of SIGVTALRM. (int send) */
  290. extern    void ndet_update_real_itimer();    /* Some real itimer related condition
  291.                        has changed.  Determine minimum wait
  292.                        and set real itimer.  Enable(disable)
  293.                        notifier auto signal catching of
  294.                        SIGALRM. (int send) */
  295. extern    NTFY_ENUM ndet_fd_send();    /* Enqueue notifications for any fds
  296.                        in (NDET_ENUM_SEND *) context.
  297.                        (NTFY_CLIENT *client,
  298.                         NTFY_CONDITION *condition,
  299.                         NTFY_ENUM_DATA context) */
  300.  
  301. extern    void ndet_set_event_processing();/* Called from dispatcher to tell
  302.                        detector that nclient is in the
  303.                        process of handling a client event
  304.                        (on == 1) or done handling a client
  305.                        event (on == 0).
  306.                        (Notify_client nclient, int on) */
  307. /*
  308. ********************** Interval Timer Algorithms *************************
  309. For both types of interval timers:
  310. 1) When an interval timer expires for a client, the reset value is used
  311. to set the interval value.
  312.  
  313. 2) The smallest interval of all clients is used to reset the process
  314. interval timer.
  315.  
  316. 3) Before recomputing a process timer, use the TIME_DIF (see below)
  317. to update it_value in all the clients.  Any it_values <= zero are sent
  318. notifications.
  319.  
  320. 4) When a process timer expires, simply recomputing the process timer
  321. has the side effect of sending notifications.
  322.  
  323. Note: Polling is inefficient if not special cased.  Polling is separate
  324. from interval timer computation.  Polling is implemented as something
  325. related to the select timer.
  326.  
  327. 4) Caution:
  328.  
  329.     a) Signals being received while recomputing interval causing
  330.        duplicate notifications.
  331.  
  332.     b) Granularity of very short intervals may cause overlap
  333.        of notification and determining the next one.
  334.  
  335. For process virtual time interval timers TIME_DIF is the value used
  336. to set the process timer.
  337.  
  338. Computation of real time interval timers differs from process virtual
  339. time interval timers in that the real timer interval timer must be exact
  340. enough so that if a client sets it to be the difference between now and
  341. 5:00am that he would be notifier at 5:00am.  To avoid cummulative delay
  342. errors, we make real time interval timers relative to the time of day at
  343. which they were set.  Thus, when setting a client timer
  344. (ntfy_set_itimer_func or resetting from it_value), note the tod
  345. (time-of-day) and the original it_value.  TIME_DIF is the difference
  346. from the current tod and the original tod.  The original it_value-
  347. TIME_DIF gives the current it_value.
  348.  
  349.  
  350. ********************** Handling Supplementary Signals ********************
  351. In notification loop
  352. 1) Find fd that is async.
  353. 2) Set SIGIO signal catcher with ndet_sigio as function.
  354. 3) Ndet_sigio will search all conditions in its client for fds which match
  355. ndet_fasync_mask.
  356. 4) Any that match have a FIOCNREAD done to see if any input for that fd.
  357. 5) Send notification if so, else ignore.
  358. ********************** Clients Considerations ****************************
  359. Changing a condition during a notification:
  360.  
  361. 1) Changes can come any time, synchronously or asynchronously,
  362. as long as they are notification derived, i.e., a client didn't
  363. catch a signal and call the notifier himself. 
  364.  
  365. 2) Condition changes affect what will be waited on next time through
  366. the notication loop.  If you remove a condition asynchronously then
  367. it wouldn't be notified.  If you add a condition asynchronously that
  368. happens to be selected on this time already then you may get a
  369. notification this time around the notication loop instead of next time.
  370.  
  371. 3) Multiple changes to the same condition are applied immediately, i.e.,
  372. the last change that the notifier got will be the current one.
  373.  
  374. 4) A notify_post_destroy or notify_die command applies immediately.
  375. Callers of these routines should do so during synchronous processing.
  376. To do so otherwise is an error (NOTIFY_CANT_INTERRUPT).  This is because
  377. the notifier refuses to call out to a client that may be in an unsafe
  378. condition unless the client has stated explicitely that it will
  379. worry about safety himself, e.g., asynchronously signals and
  380. immediate client events.
  381. */
  382.  
  383. #endif    NDET_DEFINED
  384.  
  385.